package com.example.chatweb.repository;

import co.elastic.clients.elasticsearch.ElasticsearchClient;
import co.elastic.clients.elasticsearch._types.Refresh;
import co.elastic.clients.elasticsearch.core.*;
import co.elastic.clients.elasticsearch.core.search.Hit;
import co.elastic.clients.elasticsearch.core.search.TotalHits;
import co.elastic.clients.elasticsearch.ingest.GrokProcessor;
import co.elastic.clients.elasticsearch.ingest.Processor;
import co.elastic.clients.elasticsearch.ingest.PutPipelineRequest;
import co.elastic.clients.elasticsearch.ingest.PutPipelineResponse;
import co.elastic.clients.json.jackson.JacksonJsonpMapper;
import co.elastic.clients.transport.ElasticsearchTransport;
import co.elastic.clients.transport.rest_client.RestClientTransport;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.HttpHost;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.elasticsearch.client.RestClient;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.stereotype.Repository;

import javax.net.ssl.SSLContext;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Repository
public class ArticleRepository<T> {

    private ElasticsearchClient client;

    public ArticleRepository() {
        this.makeConnection();
    }
    //私有同步方法，建立和es数据库连接
    private synchronized void makeConnection(){

        RestClient restClient = RestClient
                .builder(new HttpHost("172.21.151.112", 9200, "http"))
                .build();

        // Create the transport and the API client
        ElasticsearchTransport transport = new RestClientTransport(restClient, new JacksonJsonpMapper());
        this.client = new ElasticsearchClient(transport);
    }

    public ElasticsearchClient getClient() {
        return client;
    }

    public List<T> getListByFields(String index, List<String> fields, String value, int pageNo, int pageSize, Class<T> clazz) throws IOException {
        SearchRequest searchRequest = new SearchRequest.Builder()
                .index(index)
                .from((pageNo-1)*pageSize)
                .size(pageSize)
                .query(q -> q.multiMatch(t -> t.fields(fields).query(value)))
                .build();
        SearchResponse<T> searchResponse = this.getClient().search(searchRequest, clazz);
        List<Hit<T>> hits = searchResponse.hits().hits();
        System.out.println(hits);
        assert searchResponse.hits().total() != null;
        return hits.stream().map(Hit::source).collect(Collectors.toList());
    }

    public long insert(Object obj, String index, Class<T> clazz) throws IOException {
        IndexRequest<T> indexRequest = new IndexRequest.Builder<T>()
                .index(index)
                .document(clazz.cast(obj))
                .refresh(Refresh.WaitFor)
                .build();
        IndexResponse indexResponse = this.getClient().index(indexRequest);
//        log.info("insert version: "+indexResponse.version());
        return indexResponse.version();
    }

    public long delete(String id, String index) throws IOException {
        DeleteRequest deleteRequest = new DeleteRequest.Builder()
                .index(index)
                .id(id)
                .build();
        DeleteResponse deleteResponse = this.getClient().delete(deleteRequest);
//        log.info("insert version: "+deleteResponse.version());
        return  deleteResponse.version();

    }

    public long update(Object obj, String id, String index, Class<T> clazz) throws IOException {
        IndexRequest<T> indexRequest = new IndexRequest.Builder<T>()
                .index(index)
                .id(id)
                .document(clazz.cast(obj))
                .refresh(Refresh.WaitFor)
                .build();
        IndexResponse indexResponse = this.getClient().index(indexRequest);
//        log.info("insert version: "+indexResponse.version());
        return indexResponse.version();

    }

    public T getById(String id, String index, Class<T> clazz) throws IOException {
        SearchRequest searchRequest = new SearchRequest.Builder()
                .index(index)
                .query(q -> q.ids(v->v.values(id)))
                .build();
        SearchResponse<T> searchResponse = this.getClient().search(searchRequest, clazz);
        List<Hit<T>> hits = searchResponse.hits().hits();
        assert hits.size()>0;
        return hits.get(0).source();
    }

    public List<T> getList(String index, int pageNo, int pageSize, Class<T> clazz) throws IOException {
        SearchRequest searchRequest = new SearchRequest.Builder()
                .index(index)
                .from((pageNo-1)*pageSize)
                .size(pageSize)
                .build();
        SearchResponse<T> searchResponse = this.getClient().search(searchRequest, clazz);
        List<Hit<T>> hits = searchResponse.hits().hits();
        return hits.stream().map(Hit::source).collect(Collectors.toList());
    }

//    public PageData<T> getList(String index, int pageNo, int pageSize, Class<T> clazz) throws IOException {
//        SearchRequest searchRequest = new SearchRequest.Builder()
//                .index(index)
//                .from((pageNo-1)*pageSize)
//                .size(pageSize)
//                .build();
//        return searchResponse2PageData(pageNo, pageSize, clazz, searchRequest);
//    }
//
//    public PageData<T> getListByField(String index, String field, String value, int pageNo, int pageSize, Class<T> clazz) throws IOException {
//        SearchRequest searchRequest = new SearchRequest.Builder()
//                .index(index)
//                .from((pageNo-1)*pageSize)
//                .size(pageSize)
//                .query(q -> q.match(t -> t.field(field).query(value)))
//                .build();
//        return searchResponse2PageData(pageNo, pageSize, clazz, searchRequest);
//    }

//    @NotNull
//    private PageData<T> searchResponse2PageData(int pageNo, int pageSize, Class<T> clazz, SearchRequest searchRequest) throws IOException {
//        SearchResponse<T> searchResponse = this.getClient().search(searchRequest, clazz);
//        List<Hit<T>> hits = searchResponse.hits().hits();
//        assert searchResponse.hits().total() != null;
//        return new PageData<>(
//                hits.stream().map(Hit::source).collect(Collectors.toList()),
//                pageNo,
//                pageSize,
//                searchResponse.hits().total().value()
//        );
//    }

//    public int getNumber(String index, Class<T> clazz) throws IOException {
//        return this.getList(index, clazz).size();
//    }


    public void testPipeline() throws IOException {
        Map<String, String> patternMap = new HashMap<String, String>(){{
            put("111", "222");
            put("222", "444");
        }};
        PutPipelineRequest putPipelineRequest = new PutPipelineRequest.Builder()
                .id("test-javacli")
                .description("description")
                .processors(new Processor(new GrokProcessor.Builder()
                        .field("field111")
                        .patterns("pattern1", "pattern2")
                        .patternDefinitions(patternMap)
                        .build()))
                .build();
        PutPipelineResponse res = this.getClient().ingest().putPipeline(putPipelineRequest);
        System.out.println(res.toString());
    }
}
